package edu.ynu.se.xiecheng.achitectureclass.GreenHouse.scheduler;

import edu.ynu.se.xiecheng.achitectureclass.GreenHouse.GreenhouseEntity.*;
import edu.ynu.se.xiecheng.achitectureclass.GreenHouse.GreenhouseService.*;

import edu.ynu.se.xiecheng.achitectureclass.GreenHouse.utils.ImageDownloader;
import edu.ynu.se.xiecheng.achitectureclass.GreenHouse.utils.ImageUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.*;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Component
public class DataFetchScheduler {

    @Value("${image.storage.path}")
    private String imageStoragePath;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private HumidityDataService humidityDataService;

    @Autowired
    private NitrogenDataService nitrogenDataService;

    @Autowired
    private PhosphorusDataService phosphorusDataService;

    @Autowired
    private PotassiumDataService potassiumDataService;

    @Autowired
    private TemperatureDataService temperatureDataService;

    @Autowired
    private CameraDataService cameraDataService;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ImageUtils imageUtils;

    // 定义API的URL
    private static final String FBOX_API_URL = "https://fbox360.com/api/v2/dmon/value/get?boxNo=";
    private static final String YS_API_URL = "https://open.ys7.com/api/lapp/device/capture";
    private static final String FBOX_TOKEN_URL = "https://fbox360.com/idserver/core/connect/token";
    private static final String YS_TOKEN_URL = "http://42.193.14.241:7000/ysapi/subAccount/getToken";

    // 定义传感器ID列表（根据项目要求选择5个传感器）
    private static final List<String> SENSOR_IDS = Arrays.asList(
            "327061586065758005", // 土壤含水率
            "327061586065758015", // 土壤温度
            "327061586065758008", // 土壤氮含量
            "327061586065758009", // 土壤磷含量
            "327061586065758010"  // 土壤钾含量
    );

    // 定义摄像头设备序列号
    private static final String CAMERA_SERIAL = "L29334649";

    // 定时任务：每隔5分钟获取一次土壤检测数据
    @Scheduled(fixedRate = 300000) // 300000毫秒 = 5分钟
    public void fetchSoilData() {
        String boxNo = "300822040454"; // 大棚编号
        String url = FBOX_API_URL + boxNo;

        // 获取 Token
        String token = getToken("fbox");
        System.out.println("fobox-token:"+token);
        if (token == null) {
            System.out.println("Failed to get token for fbox.");
            return;
        }

        // 构造请求体
        Map<String, List<String>> requestBody = new HashMap<>();
        requestBody.put("ids", SENSOR_IDS);

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + token);
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 发送POST请求
        HttpEntity<Map<String, List<String>>> requestEntity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(
                url, HttpMethod.POST, requestEntity, new ParameterizedTypeReference<List<Map<String, Object>>>() {});

        // 处理返回的数据
        if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
            for (Map<String, Object> sensorData : response.getBody()) {
                String sensorId = (String) sensorData.get("id");
                String sensorName = (String) sensorData.get("name");
                Double sensorValue = Double.parseDouble(sensorData.get("value").toString());

                // 根据传感器类型存储数据
                switch (sensorName) {
                    case "土壤含水率":
                        saveHumidityData(sensorId, sensorName, sensorValue);
                        break;
                    case "土壤温度":
                        saveTemperatureData(sensorId, sensorName, sensorValue);
                        break;
                    case "土壤氮含量":
                        saveNitrogenData(sensorId, sensorName, sensorValue);
                        break;
                    case "土壤磷含量":
                        savePhosphorusData(sensorId, sensorName, sensorValue);
                        break;
                    case "土壤钾含量":
                        savePotassiumData(sensorId, sensorName, sensorValue);
                        break;
                }
            }
        }
    }

    // 定时任务：每隔10分钟抓取一次摄像头图片

    @Scheduled(fixedRate = 600000) // 600000毫秒 = 10分钟
    public void fetchCameraImage() {
        try {
            // 获取 Token
            String token = getToken("ys");
            System.out.println("token:"+token);
            if (token == null) {
                System.out.println("Failed to get token for ys.");
                return;
            }

            // 构造请求体
            MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
            requestBody.add("accessToken", token);
            requestBody.add("deviceSerial", CAMERA_SERIAL);
            requestBody.add("channelNo", "1");
            requestBody.add("quality","1");

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

            // 发送POST请求
            HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<Map<String, Object>> response = restTemplate.exchange(
                    YS_API_URL, HttpMethod.POST, requestEntity, new ParameterizedTypeReference<Map<String, Object>>() {});

            // 处理返回的图片URL
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                Map<String, Object> data = (Map<String, Object>) responseBody.get("data");

                if (data != null && data.containsKey("picUrl")) {
                    String picUrl = (String) data.get("picUrl");
                    System.out.println("PicUrl: " + picUrl);
                    // 生成唯一的文件名
                    String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
                    String fileName = "camera_" + timestamp + ".jpg"; // 例如：camera_20250107_212345.jpg

                    String localFilePath = imageStoragePath + fileName;

                    // 创建目录（如果不存在）
                    File directory = new File(imageStoragePath);
                    if (!directory.exists()) {
                        directory.mkdirs(); // 创建目录
                    }

                    // 下载图片到本地
                    ImageDownloader downloader = new ImageDownloader();
                    downloader.downloadImage(picUrl, localFilePath);

                    // 将图片转换为 Base64
                    ImageUtils imageUtils = new ImageUtils();
                    String picBase64 = imageUtils.convertImageToBase64(localFilePath);

                    // 保存摄像头数据
                    saveCameraData(picUrl, picBase64);
                } else {
                    System.out.println("Failed to get picUrl from response.");
                }
            } else {
                System.out.println("Failed to get response from YS API: " + response.getStatusCode());
            }
        } catch (Exception e) {
            System.err.println("Error in fetchCameraImage: " + e.getMessage());
            e.printStackTrace(); // 打印堆栈信息以便调试
        }
    }

    // 获取 Token
    private String getToken(String tokenType) {
        // 从数据库获取最新的 Token
        Token token = tokenService.findByTokenType(tokenType);
        System.out.println("测试token:"+token);
        if (token != null && !isTokenExpired(token)) {
            return token.getTokenValue(); // 如果 Token 未过期，直接返回
        }

        // 如果 Token 过期或不存在，重新获取
        String newToken = fetchNewToken(tokenType);
        if (newToken != null) {
            // 保存新的 Token 到数据库
            saveToken(tokenType, newToken);
            return newToken;
        }

        return null; // 获取 Token 失败
    }

    // 检查 Token 是否过期
    private boolean isTokenExpired(Token token) {
        Date expirationTime = token.getExpirationTime();
        Date now = new Date();
        System.out.println("Expiration Time: " + expirationTime);
        System.out.println("Current Time: " + now);
        if (expirationTime == null) {
            return true; // 如果没有过期时间，认为已经过期
        }
        return expirationTime.before(now);
    }

    // 获取新的 Token
    private String fetchNewToken(String tokenType) {
        if ("fbox".equals(tokenType)) {
            return fetchFboxToken();
        } else if ("ys".equals(tokenType)) {
            return fetchYsToken();
        }
        return null;
    }

    // 获取 Fbox Token
    private String fetchFboxToken() {
        // 构造请求体
        MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
        requestBody.add("scope", "fbox");
        requestBody.add("client_id", "68db2e8bda8d47b5b5db7eaf71c7dcdd");
        requestBody.add("client_secret", "76dc724c95004acab25482d344dab407");
        requestBody.add("grant_type", "client_credentials");

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        // 发送POST请求
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<Map<String, Object>> response = restTemplate.exchange(
                FBOX_TOKEN_URL, HttpMethod.POST, requestEntity, new ParameterizedTypeReference<Map<String, Object>>() {});

        // 处理返回的 Token
        if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
            return (String) response.getBody().get("access_token");
        }
        return null;
    }

    // 获取 Ys Token
    private String fetchYsToken() {
        // 构造请求体
        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("accountId", "1ca7f0ab24ba41b291346347ec30140e");

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 发送POST请求
        HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<Map<String, Object>> response = restTemplate.exchange(
                YS_TOKEN_URL, HttpMethod.POST, requestEntity, new ParameterizedTypeReference<Map<String, Object>>() {});

        // 处理返回的 Token
        if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
            Map<String, Object> data = (Map<String, Object>) response.getBody().get("data");
            if (data != null && data.containsKey("accessToken")) {
                return (String) data.get("accessToken");
            } else {
                throw new RuntimeException("accessToken not found in response data");
            }
        } else {
            throw new RuntimeException("Failed to get Ys Token: " + response.getStatusCode());
        }
    }

    // 保存 Token 到数据库
    private void saveToken(String tokenType, String tokenValue) {
        Token token = new Token();
        token.setTokenValue(tokenValue);
        token.setTokenType(tokenType);
        token.setScope(tokenType);
        token.setExpirationTime(calculateExpirationTime(tokenType)); // 计算过期时间
        tokenService.POST(token);
    }

    // 计算 Token 的过期时间
    private Date calculateExpirationTime(String tokenType) {
        Calendar calendar = Calendar.getInstance();
        if ("fbox".equals(tokenType)) {
            calendar.add(Calendar.SECOND, 7200); // Fbox Token 有效期为 2 小时
        } else if ("ys".equals(tokenType)) {
            calendar.add(Calendar.MILLISECOND, 7200000*12); // Ys Token 有效期为 24 小时
        }
        return calendar.getTime();
    }

    // 保存湿度数据
    private void saveHumidityData(String sensorId, String sensorName, Double value) {
        HumidityData humidityData = new HumidityData();
        humidityData.setName(sensorName);
        humidityData.setValue(value);
        humidityData.setDeviceInfo(deviceService.getByDeviceId(sensorId)); // 使用 getByDeviceId
        humidityDataService.POST(humidityData);
    }

    // 保存温度数据
    private void saveTemperatureData(String sensorId, String sensorName, Double value) {
        TemperatureData temperatureData = new TemperatureData();
        temperatureData.setName(sensorName);
        temperatureData.setValue(value);
        temperatureData.setDeviceInfo(deviceService.getByDeviceId(sensorId)); // 使用 getByDeviceId
        temperatureDataService.POST(temperatureData);
    }

    // 保存氮含量数据
    private void saveNitrogenData(String sensorId, String sensorName, Double value) {
        NitrogenData nitrogenData = new NitrogenData();
        nitrogenData.setName(sensorName);
        nitrogenData.setValue(value);
        nitrogenData.setDeviceInfo(deviceService.getByDeviceId(sensorId)); // 使用 getByDeviceId
        nitrogenDataService.POST(nitrogenData);
    }

    // 保存磷含量数据
    private void savePhosphorusData(String sensorId, String sensorName, Double value) {
        PhosphorusData phosphorusData = new PhosphorusData();
        phosphorusData.setName(sensorName);
        phosphorusData.setValue(value);
        phosphorusData.setDeviceInfo(deviceService.getByDeviceId(sensorId)); // 使用 getByDeviceId
        phosphorusDataService.POST(phosphorusData);
    }

    // 保存钾含量数据
    private void savePotassiumData(String sensorId, String sensorName, Double value) {
        PotassiumData potassiumData = new PotassiumData();
        potassiumData.setName(sensorName);
        potassiumData.setValue(value);
        potassiumData.setDeviceInfo(deviceService.getByDeviceId(sensorId)); // 使用 getByDeviceId
        potassiumDataService.POST(potassiumData);
    }

    // 保存摄像头数据
    private void saveCameraData(String picUrl, String picBase64) {
        try {
            CameraData cameraData = new CameraData();
            cameraData.setPicUrl(picUrl);
            cameraData.setPicBase64(picBase64);
            cameraData.setDevice(deviceService.getByDeviceId(CAMERA_SERIAL)); // 使用 getByDeviceId
            cameraDataService.POST(cameraData);
        } catch (Exception e) {
            System.err.println("Error saving camera data: " + e.getMessage());
        }
    }
}